﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.Text.RegularExpressions;
using BlogHunter.Manager;
using System.Net;
using System.IO;
using System.IO.Compression;

namespace BlogHunter
{
    class NeteaseBlog : Blog
    {
        private string _dwrSpliceRule;
        public string DWRSpliceRule
        {
            get { return _dwrSpliceRule; }
            set { _dwrSpliceRule = value; }
        }

        public NeteaseBlog()
        {
            //Set Properties.
            AutoSplice = Convert.ToBoolean(ConfigurationSettings.AppSettings["NeteaseBlogHomePageAutoSplice"]);
            SpliceRule = ConfigurationSettings.AppSettings["NeteaseBlogHomePageSpliceRule"];
            OutPath = ConfigurationSettings.AppSettings["NeteaseOutPath"];

            EncodingCharset = ConfigurationSettings.AppSettings["NeteaseEncodingCharset"];

            BlogInfoRegex = new Regex(@"permalink=""([^""]*)"";([^;]*);([^;]*);([^;]*);...publishTimeStr=""([^""]*)"";([^;]*);([^;]*);...shortPublishDateStr=""([^""]*)"";([^;]*);([^;]*);...title=""([^""]*)""");
            LinkRegexGroupNum = Convert.ToInt32(ConfigurationSettings.AppSettings["NeteaseLinkRegexGroupNum"]);
            TitleRegexGroupNum = Convert.ToInt32(ConfigurationSettings.AppSettings["NeteaseTitleRegexGroupNum"]);

            DateRegexGroupNum = Convert.ToInt32(ConfigurationSettings.AppSettings["NeteaseDateRegexGroupNum"]);
            TimeRegexGroupNum = Convert.ToInt32(ConfigurationSettings.AppSettings["NeteaseTimeRegexGroupNum"]);

            DWRSpliceRule = ConfigurationSettings.AppSettings["NeteaseBlogDWRSpliceRule"];
            ArticleLinkSpliceRule = ConfigurationSettings.AppSettings["NeteaseArticleLinkSpliceRule"];

            ArticleCountPerPage = Convert.ToInt32(ConfigurationSettings.AppSettings["NeteaseArticleCountPerPage"]);
        }

        private string GetNeteaseUserId()
        {
            string userId = string.Empty;
            string homepageContent = HTMLContentManager.GetHTMLContent(BlogHomePage, Encoding.GetEncoding(EncodingCharset));

            Regex userIdRegex = new Regex(@"userId:([0-9]*)");
            Match myMatch1 = userIdRegex.Match(homepageContent);
            if (myMatch1.Success)
            {
                userId = myMatch1.Groups[1].ToString().Trim();
            }

            return userId;
        }

        private void SetNeteasePostingParams(string userId, int currentPageCount, int articleCount)
        {
            Dictionary<string, string> pars = new Dictionary<string, string>();
            pars.Add("callCount", "1");
            pars.Add("scriptSessionId", "1234");
            pars.Add("c0-scriptName", "BlogBeanNew");
            pars.Add("c0-methodName", "getBlogs");
            pars.Add("c0-id", "0");
            pars.Add("c0-param0", "number:" + userId);
            pars.Add("c0-param1", "number:" + currentPageCount.ToString());
            pars.Add("c0-param2", "number:" + articleCount.ToString());
            pars.Add("batchId", "1234567");

            PostingParams = pars;
        }

        private HttpWebResponse SendPostRequest(string url, Dictionary<string, string> pars)
        {
            HttpWebRequest request = HTMLContentManager.CreatePostHttpWebRequest(url);
            request.Method = "post";

            request.ContentType = "text/plain";

            StringBuilder sbRequestPars = new StringBuilder();
            foreach (KeyValuePair<string, string> par in pars)
            {
                sbRequestPars.AppendFormat("{0}={1}&", par.Key, par.Value);
            }

            sbRequestPars = new StringBuilder(sbRequestPars.ToString(0, sbRequestPars.Length - 1));
            byte[] data = Encoding.GetEncoding(EncodingCharset).GetBytes(sbRequestPars.ToString());
            request.ContentLength = data.Length;

            Stream myStream = request.GetRequestStream();
            myStream.Write(data, 0, data.Length);
            myStream.Close();

            HttpWebResponse res = null;

            try
            {
                res = request.GetResponse() as HttpWebResponse;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return res;
        }


        public override void GetAllNewBlogInfoList()
        {
            //Loop Each Page to Get BlogInfo List

            string userId = GetNeteaseUserId();

            int nextPageCount = 0;

            do
            {
                nextPageCount = GetNewBlogInfoList(nextPageCount, ArticleCountPerPage, userId);
            } while (nextPageCount != -1);
        }


        public int GetNewBlogInfoList(int currentPageCount, int articleCount, string userId)
        {
            bool needUpadteFlag = true;
            int nextPageCount = currentPageCount + articleCount;

            SetNeteasePostingParams(userId, currentPageCount, articleCount);

            HttpWebResponse res = null;

            try
            {
                res = SendPostRequest(DWRSpliceRule.Replace("$BLOGNAME$", InputBlogName), PostingParams);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            if (res != null)
            {
                //Output to file
                Stream st = res.GetResponseStream();
                if (res.ContentEncoding.ToLower().Contains("gzip"))
                {
                    st = new GZipStream(st, CompressionMode.Decompress);
                }
                StreamReader sr = new StreamReader(st, Encoding.GetEncoding(EncodingCharset));

                string inputString = Regex.Unescape(sr.ReadToEnd());

                //Regex to extract data
                Match myMatch1 = BlogInfoRegex.Match(inputString);

                if (!myMatch1.Success)
                {
                    needUpadteFlag = false;
                }

                while (myMatch1.Success)
                {
                    BlogInfo newBlogInfo = new BlogInfo();

                    string strTitle = myMatch1.Groups[TitleRegexGroupNum].Value;
                    Console.WriteLine(strTitle);
                    newBlogInfo.ArticleTitle = strTitle;

                    string strLink = myMatch1.Groups[LinkRegexGroupNum].Value;
                    Console.WriteLine(strLink);
                    newBlogInfo.ArticleLink = new Uri(new Uri(ArticleLinkSpliceRule.Replace("$BLOGNAME$", InputBlogName)), strLink).ToString();

                    string strTimeString = myMatch1.Groups[TimeRegexGroupNum].Value;
                    string strDateString = myMatch1.Groups[DateRegexGroupNum].Value;

                    Console.WriteLine(strDateString + " " + strTimeString);

                    DateTime blogDatetime = DateTime.Now;
                    DateTime.TryParse(strDateString.Trim() + " " + strTimeString.Trim(), out blogDatetime);
                    newBlogInfo.ArticleDateTime = blogDatetime;


                    //If exists LatestPublishDate, break the while loop if newBlogInfo.ArticleDateTime < LatestPublishDate
                    if (LatestPublishDate != null && DateTime.Compare(newBlogInfo.ArticleDateTime, LatestPublishDate) < 0)
                    {
                        needUpadteFlag = false;
                        break;
                    }

                    //Add New BlogInfo to NewBlogInfoList if it doesn't exist in PreviousBlogInfoList
                    if (PreviousBlogInfoList != null && !PreviousBlogInfoList.Contains(newBlogInfo))
                    {
                        NewBlogInfoList.Add(newBlogInfo);
                    }
                    else
                    {
                        needUpadteFlag = false;
                        break;
                        //Console.WriteLine("Reduplicate BlogInfo, Need to break the loop.");
                    }

                    myMatch1 = myMatch1.NextMatch();
                }
            }
            else
            {
                needUpadteFlag = false;
            }

            if (!needUpadteFlag)
                nextPageCount = -1;

            return nextPageCount;
        }
    }
}
